<template>
  <div>
    <el-button type="warning" size="default" @click="handleTrige"
      >Chapter 4响应式系统实现</el-button
    >
    <div class="testData"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted } from "vue";
onMounted(() => {
  effect(() => {
    const element = document.querySelector(".testData");
    if (element) {
      element.textContent = obj.text;
    }
  });
  console.log("🚀 ~ onMounted ~ data:", data);
});
const handleTrige = () => {
  obj.text = "测试一下";
  console.log("🚀 ~ handleTrige ~ data:", data);
};

let activeEffect: Function | null = null;
const bucket = new WeakMap();

const effect = (fn: Function) => {
  activeEffect = fn;
  fn();
};

const data = { text: "hello world" };
const obj = new Proxy(data, {
  get(target, key) {
    track(target, key);
    //@ts-ignore
    return target[key];
  },
  //@ts-ignore
  set(target, key, value) {
    //@ts-ignore
    target[key] = value;
    trigger(target, key);
    return true;
  },
});

const track = (target: any, key: any) => {
  if (!activeEffect) {
    return;
  }
  let depMap = bucket.get(target);
  if (!depMap) {
    bucket.set(target, (depMap = new Map()));
  }
  let deps = depMap.get(key);
  if (!deps) {
    depMap.set(key, (deps = new Set()));
  }
  deps.add(activeEffect);
};

const trigger = (target: any, key: any) => {
  const depsMap = bucket.get(target);
  if (!depsMap) {
    return;
  }
  const effects = depsMap.get(key);
  effects && effects.forEach((fn: any) => fn());
};
</script>
<style lang="scss" scoped>
.testData {
  height: 100px;
  width: 100px;
  background-color: cadetblue;
  color: #fff;
}
</style>
